import marimo

__generated_with = "0.9.27"
app = marimo.App(width="medium")


@app.cell
def __():
    import marimo as mo
    return (mo,)


@app.cell
def __():
    # python 2使用中文，需增加注释，python 3不需要


    # -*- coding: utf-8 -*-



    return


@app.cell
def __(mo):
    mo.md(
        r"""
        python能自由改变 变量的类型，称为动态类型

        原本想将True赋给x，结果赋给了y，这种错误不容易检查



        跳转最主要的功能，就是选择性的执行，有了 if 和while两种语法，跳转就再无必要，现代语言中跳转已废除。


        当函数是数据容器是，函数内外部只存在一个容器，所以函数内部对容器的操作，会影响到外部，list是数据容器


        修改 PYTHONPATH环境变量，能直接导入自己写的包

        linux，修改`/home/.bashrc`，增加

        ```
        export PYTHONPATH=/home/python_module:$PYTHONPATH
        ```


        字符串是特殊的元组，可以执行元组的方法，字符串的一些方法能改变字符串，它们是删除原来的字符串，创建新字符串
        """
    )
    return


@app.cell
def __(mo):
    mo.md(
        r"""
        python使用模块包

        将功能相似的文件放在文件夹 this_dir中

        引入this_dir中的module模块

        import this_dir.module

        文件夹中必须包含一个\__init__.py文件提醒python该文件夹是模块包，\__init__.py可以是空文件

        每个模块对象都有一个__name__属性，记录模块名字

        当.py文件作为主程序运行时，他的__name__属性是main
        """
    )
    return


@app.cell
def __():
    def pkg_keyword(**args):
        print(type(args))
        print(args)
    return (pkg_keyword,)


@app.cell
def __(pkg_keyword):
    pkg_keyword(a=1, b=9)

    # 参数是字典，不输入参数名报错
    # pkg_keyword(4,7)



    pkg_keyword(o=16, p=78, q=39)
    return


@app.cell
def __():
    def more_args(*argsb):
        print(type(argsb))
        print(argsb)
    return (more_args,)


@app.cell
def __(more_args):
    more_args(4,6)


    # 参数是tuple，输入参数名，会报错
    # more_args(a=10, b=17)


    more_args(6, 7, 8,10)
    return


@app.cell
def __():
    # 递归，源自数学归纳法
    # 必须有一个终止条件

    def gaussian_sum(n):
        if n==1:
            return 1
        else:
            return n + gaussian_sum(n-1)

    gaussian_sum(100)

    gaussian_sum(105)
    return (gaussian_sum,)


@app.cell
def __():
    # 类

    class Bird():




        def chirp(self):
            print('发出声音')



    # 继承父类
    class Chicken(Bird):

        # 继承父类方法并增加功能
        # super是内置类,能生成一个指代父类的对象
        def chirp(self):
            super().chirp()
            print('咯')



    # 根据类新建对象
    a = Bird()

    a.chirp()

    b = Chicken()

    b.chirp()
    return Bird, Chicken, a, b


@app.cell
def __(Bird):
    # 保存对象到磁盘,

    import pickle

    _a = Bird()

    # 将对象转为2进制
    # pickle_s = pickle.dumps(_a)



    # with open('obj_1.pkl','wb') as f:
    #     f.write(pickle_s)



    # dump,dumps的区别
    with open('obj_1.pkl','wb') as f:
        pickle.dump(_a, f)


    # 读出对象

    with open('obj_1.pkl','rb') as f:
        _b = pickle.load(f)



    _b.chirp()
    return f, pickle


@app.cell
def __():
    #类

    class _Bird():

        # 特殊方法, __add__(), __dict__()等
        # sound_o是外部参数, __init__有外部参数,新建对象时需要输入外部参数
        def __init__(self, sound_o):
            self.sound = sound_o
            print(f'我的声音是: {sound_o}')

        # 无论参数是否被用到,方法的第一个参数必须是self,
        # 定义方法是必须有self,调用方法时不需要传入数据
        def chirp(self):
            print(self.sound)

        # n是外部参数,方法有外部参数,调用方法时需要输入外部参数
        def chirp_repeat(self, n):
            for i in range(n):
                # self还能在一个方法内部,调用本类的其他方法
                self.chirp()

        # 特殊方法,可将对象作为函数使用
        def __call__(self):
            print('作为函数输出')


    _a = _Bird('叽叽')

    # _a.chirp()

    # _a.chirp_repeat(10)



    # 将对象作为函数使用,仍然会运行__init__
    _a()
    return


@app.cell
def __():
    # 生成器


    # 不是生成器,是一个循环对象?
    _b = type(range(10))



    def gen():
        a = 100
        yield a

        a = a*8

        yield a

        yield 1000

    _a = gen()

    _a

    # for i in gen():
    #     print(i)

    # print(_a)
    return (gen,)


@app.cell
def __():
    def gen_1():
        i = 0
        while i < 100:
            i = i+1
            yield i



    # 只有在循环中,才能取出生成器的值?
    for i in gen_1():
        print(i)
    return gen_1, i


@app.cell
def __():
    # 显示模块名


    import time

    print(time.__name__)


    import math

    print(math.__name__)
    return math, time


@app.cell
def __():
    # 类使用上下文管理器

    class Vow():
        def __init__(self, text_o):
            self.text = text_o



        # 类中加入__enter__和__exit__就可以使用上下文编辑器
        def __enter__(self):
            self.text = f'我说:{self.text}'
            return self


        def __exit__(self, exc_type, exc_value, traceback):
            self.text = f'{self.text} !'



    # 调用了__enter__方法
    # 上下文管理器，
    # 一旦结束代码块，文件就自动关闭
    with Vow('我很好') as my_vow:
        print(my_vow.text)


    # 调用了__exit__方法
    print(my_vow.text)
    return Vow, my_vow


@app.cell
def __():
    #pickel保存对象
    return


@app.cell
def __(mo):
    mo.md(r"""datetime.date类输出日期, datetime.time类输出时间""")
    return


@app.cell
def __():
    import re


    # ()内的正则,叫群,group(0)表示整个正则,group(1)表示第一个正则群
    m = re.search('output_(\d{4})', 'output_1984.txt')

    print(m.group(1))
    return m, re


@app.cell
def __(re):
    # 为正则群命名,后续通过名称查找,?P<year>,P必须大写
    _m = re.search('output_(?P<year>\d{4})', 'output_1984.txt')


    print(_m.group('year'))
    return


@app.cell
def __():
    # 特殊方法


    # 查看类的方法
    dir(list)

    # __add()__方法定义了运算符+对list的意义

    # li[3],len([1,2,3])都是通过调用特殊方法实现的
    return


@app.cell
def __(Bird):
    # 属性的覆盖，子类只包含子类中定义的属性，其他属性追朔父类的，一直追朔到object


    class _Bird():

        feather = True


        def chirp(self):
            print('发出声音')



    # 继承父类
    class _Chicken(Bird):

        def __init__(self, age_o):
            self.age = age_o


        fly = False

        def chirp(self):
            # super().chirp()
            print('咯')


    _a = _Chicken(2)


    print('===>_a')
    print(_a.__dict__)


    print('===>_Chicken')
    print(_Chicken.__dict__)


    print('===>_Bird')
    print(_Bird.__dict__)

    print('===>object')
    print(object.__dict__)
    return


@app.cell
def __():
    # 类的特性
    # 理解起来很复杂，暂时不用
    # 高级学习

    class Num():
        def __init__(self, value_o):
            self.value = value_o


        def get_neg(self):
            return -self.value


        def set_neg(self, value_m):
            self.value = -value_m


        def del_neg(self):
            print('值已删除')
            del self.value



        # neg是特性
        # 特性使用内置函数 property()来创建
        # property()最多加载4个参数，前3个为函数，后1个为说明
        # 特性会根据使用的方法，动态的改变？
        neg = property(get_neg, set_neg, del_neg, '我是负的')


    x = Num(1.1)


    # 调用参数中的get_neg
    print(x.neg)

    # 调用参数中的set_neg
    x.neg = -22

    print(x.value)

    print(Num.neg.__doc__)

    # 调用参数中的del_neg
    del x.neg
    return Num, x


@app.cell
def __(Bird):
    # 查看即时属性，看不懂
    # 高级学习

    class _Bird():

        feather = True


        def chirp(self):
            print('发出声音')



    # 继承父类
    class _Chicken(Bird):

        def __init__(self, age_o):
            self.age = age_o


        fly = False

        def __getattr__(self, name_m):
            if name_m == 'adult':
                if self.age > 1.0:
                    return True
                else:
                    return False

            else:
                raise AttributeError(name_m)


    _a = _Chicken(2)

    print(_a.adult)


    _a.age = 0.5
    print(_a.adult)


    # print(_a.male)
    return


@app.cell
def __():
    # 动态类型

    # python的一切皆是对象
    # 1是一个对象，a是指向对象的一个引用，对象是存储在内存中的实体

    _a = 1

    # id()能查看引用指向的是哪个对象，返回对象的编号

    print(id(1))
    print(id(_a))


    # 赋值时，让左侧引用，指向右侧的对象
    _a = 3
    print(id(_a))

    _a = 'ad'
    print(id(_a))


    # ==判断值是否相等，is判断是否同一个对象
    return


@app.cell
def __():
    # 从动态类型，看函数参数的传递

    # 列表，字典是可变对象，整数，浮点数，字符串是不可变对象
    # 函数参数的传递，本质上是传递的引用


    def _f(x):
        print(id(x))
        x = 100

        # id发生变化
        print(id(x))


    _a = 1

    print(id(_a))

    # 调用函数时，_a作为数据传递给函数，_x会指向_a所指对象
    # 如果_a是不可变对象，对_x的操作生成新的引用，不会影响_a
    _f(_a)

    print(_a)
    # print(id(_a))
    return


@app.cell
def __():
    def _f(x):
        print(id(x))
        x[0] = 100

        # id不变
        print(id(x))
        # print(x)


    _a = [1, 2, 3]


    # 调用函数时，_a把传递给_x，_a和_x指向同一个列表
    # 如果_a是可变对象，对_x的操作会影响_a
    _f(_a)

    print(_a)
    return


@app.cell
def __(time):
    # 时间模块

    # import time

    # 输出自1970.1.1到现在的秒数,可用于计算两个点间的时间差
    print(time.time())

    # 没有clock方法
    # print(time.clock())
    return


@app.cell
def __():
    # 函数式编程,使函数没有副作用,即这个函数运行,不会影响其他函数
    # 消灭了竞争冒险,天生适用于并行

    # 进程和线程,区别是什么?
    return


@app.cell
def __():
    # 函数作为参数

    def square_sum(a, b):
        return a**2 + b**2

    def cubic_sum(a, b):
        return a**3 + b**3

    def argument_f(f, a, b):
        return f(a, b)


    argument_f(square_sum, 3, 5)

    argument_f(cubic_sum, 3, 5)
    return argument_f, cubic_sum, square_sum


@app.cell
def __():
    # 作为参数的函数,起回调的作用
    # 以下代码运行会卡死,也看不懂

    # import tkinter as tk

    # def callback():

    #     listbox.insert(tk.END, 'hello world!')


    # if __name__ == '__main__':

    #     master = tk.Tk()

    #     button = tk.Button(master, text='ok', command=callback)

    #     button.pack()

    #     listbox = tk.Listbox(master)
    #     listbox.pack()
    #     tk.mainloop()
    return


@app.cell
def __():
    # 函数作为返回值

    def line_o():
        def line_f(x):
            return 2*x + 1
        return line_f

    my_line = line_o()

    my_line(5)

    # 跟上面等价,但看不懂5是怎么传到内部函数里的
    # line_o()返回值为line_f,line_f(5)就是11,这样理解?
    line_o()(5)
    return line_o, my_line


@app.cell
def __():
    # 闭包

    # 函数+环境变量就是闭包
    # b的两个值,b=5有效,为什么?

    def _line_o():

        # b是line_f的环境变量
        b = 15

        def line_f(x):
            return 2*x + b

        b = 5
        return line_f

    _my_line = _line_o()

    _my_line(5)
    return


@app.cell
def __():
    # 闭包简化函数,line_sp代替line_1到line_4

    def line_1(x):
        return x + 1

    def line_2(x):
        return 4*x + 1

    def line_3(x):
        return 5*x + 10

    def line_4(x):
        return -2*x - 6



    def line_sp(a, b):
        def line(x):
            return a*x + b

        return line


    line_1p = line_sp(1, 1)
    line_2p = line_sp(4, 1)
    line_3p = line_sp(5, 10)
    line_4p = line_sp(-2, -6)


    line_1p(5), line_1(5)

    line_2p(5), line_2(5)

    line_3p(5), line_3p(5)

    # line_4p(5), line_4(5)
    return (
        line_1,
        line_1p,
        line_2,
        line_2p,
        line_3,
        line_3p,
        line_4,
        line_4p,
        line_sp,
    )


@app.cell
def __():
    #闭包减少参数，
    # 高级学习
    return


@app.cell
def __():
    #装饰器

    def deco(old_f):
        def new_f(a, b):
            print('input', a, b)
            return old_f(a, b)
        return new_f


    # 装饰器是一个闭包，那么用在类中的装饰器其实都是预定义好的闭包？
    @deco
    def _square_sum(a, b):
        return a**2 + b**2


    # 在函数定义的时候加装饰器
    @deco
    def _square_diff(a, b):
        return a**2 - b**2

    @deco
    def _square_sum_3(a, b, c):
        return a**2 + b**2 + c**2


    _square_sum(3, 4)


    # 使用装饰器等价于
    _square_sum = deco(_square_sum)
    _square_sum(3, 4)




    # 需注意闭包内函数参数与装饰器函数，参数个数的一致
    # _square_sum_3(3, 4)
    return (deco,)


@app.cell
def __(time):
    # 装饰器，在新函数内部调用旧函数，保留旧函数功能


    # 给旧函数增加显示运行时间的功能
    def decorator_time(old_f):
        def new_f(*arg, **dict_arg):
            t1 = time.time()
            result = old_f(*arg, **dict_arg)
            t2 = time.time()
            print('time: ', t2 - t1)
            return result
        return new_f
    return (decorator_time,)


@app.cell
def __():
    # 带参装饰器

    # 带参装饰器需要3层，能否使用2层？
    def pre_str(pre=''):
        def decorator(old_f):
            def new_f(a, b):
                print(f'{pre} input, {a}, {b}')
                return old_f(a, b)
            return new_f
        return decorator


    @pre_str('^_^')
    def _square_sum(a, b):
        return a**2 + b**2


    @pre_str('T_T')
    def _square_diff(a, b):
        return a**2 - b**2


    _square_sum(3, 9)
    _square_diff(6, 2)
    return (pre_str,)


@app.cell
def __():
    # 装饰类
    # 高级学习

    def dec_class(any_class):
        class New_c():
            def __init__(self, age):
                self.total_disp = 0
                self.wrapped = any_class(age)

            def display(self):
                self.total_disp += 1
                print('total display', self.total_disp)
                self.wrapped.display()

        return New_c



    @dec_class
    class _Bird():

        def __init__(self, age_o):
            self.age = age_o

        def display(self):
            print('我的年龄是', self.age)


    eagle_lord = _Bird(5)
    for _i in range(3):
        eagle_lord.display()
    return dec_class, eagle_lord


@app.cell
def __():
    # 高阶函数，能处理函数的函数，以函数为参数
    # map函数

    data_l = [1, 3, 5, 6]

    # 将lambda函数作用在_data_l的每个元素上，返回生成器
    _result = map(lambda x: x+3, data_l)
    _result
    print(_result)
    return (data_l,)


@app.cell
def __(data_l, square_sum):
    # map使用多参函数,以列表元素多的，自动舍去

    data_l2 = [2, 4, 6, 8, 9]

    _result = map(square_sum, data_l, data_l2)
    _result


    # 多个列表，会报错
    # _result = map(lambda x: x+3, data_l, data_l2)
    # _result


    # map可以代替for循环，如何取出map的值？
    for _i in _result:
        print(_i)
    return (data_l2,)


@app.cell
def __():
    # filter函数

    def larger_100(a):
        if a > 100:
            return True

        else:
            return False

    # 过滤返回值为True的元素
    for _i in filter(larger_100, [10, 56, 101, 500]):
        print(_i)
    return (larger_100,)


@app.cell
def __():
    # reduce()函数，高级学习
    return


@app.cell
def __():
    # 并行处理，高级学习
    return


@app.cell
def __():
    # 生成器表达式，用于简单的生成器

    _gen = (x for x in range(4))


    # 列表表达式,注意区别
    _list = [x**2 for x in range(10)]


    # 字典表达式
    _d = {k: v for k,v in enumerate('Vamei') if v not in 'Vi'}



        # enumerate('Vamei'):
        #     enumerate 函数会生成一个迭代器，返回字符串 'Vamei' 中每个字符的索引和值。结果类似于 [(0, 'V'), (1, 'a'), (2, 'm'), (3, 'e'), (4, 'i')]。

        # 字典推导式:
        #     {k: v for k, v in ...} 用于创建字典，其中 k 是键，v 是值。

        # 条件过滤:
        #     if v not in 'Vi' 用于过滤掉 'V' 和 'i'。



    _d

    # 迭代器
    for _i in(x**2 for x in range(10)):
        print(_i)


    # 列表
    for _i in[x**2 for x in range(10)]:
        print(_i)


    type(_gen)
    return


@app.cell
def __():
    # 懒惰求值，高级学习
    return


@app.cell
def __():
    # itertools包，更多迭代器生成方法

    import itertools as it


    # 起始5，每次+2
    _a = it.count(5, 2)


    # a,b,c,d循环
    _a = it.cycle('abcd')

    # 无限重复
    _a = it.repeat(1.34)

    # 重复5次
    _a = it.repeat(10, 5)


    # 合并
    _a = it.chain([1, 2, 3], [4, 5, 7])


    _a = it.product('abc', [1, 2])



    # 其他迭代器高级学习

    for _i in _a:
        print(_i)
    return (it,)


if __name__ == "__main__":
    app.run()
